﻿using SharpDX.Direct3D9;
using SharpSnap.Plugins;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace DirectXCapture
{
    public sealed class DirectXCapturePlugin : ICapturePlugin
    {
        [DllImport("user32.dll", SetLastError = false)]
        static extern IntPtr GetDesktopWindow();

        private Direct3D direct3D;

        private Device device;

        private AdapterInformation adapter;

        // TODO: check for exceptions
        public DirectXCapturePlugin()
        {
            this.direct3D = new Direct3D();

            PresentParameters parameters = new PresentParameters();
            parameters.InitDefaults();
            parameters.Windowed = true;
            parameters.SwapEffect = SwapEffect.Discard;

            this.device = new Device(this.direct3D, 0, DeviceType.Reference, GetDesktopWindow(), CreateFlags.SoftwareVertexProcessing, parameters);

            // TODO: add multi-monitor support
            this.adapter = this.direct3D.Adapters[0];
        }

        public async Task<Bitmap> Capture(Rectangle region)
        {
            Surface target = Surface.CreateOffscreenPlain(device, 1680, 1050, Format.A8R8G8B8, Pool.Scratch);
            device.GetFrontBufferData(0, target);
            SharpDX.DataRectangle r = target.LockRectangle(new SharpDX.Rectangle(region.X, region.Y, region.Width, region.Height), LockFlags.ReadOnly);

            Bitmap bmp = new Bitmap(region.Width, region.Height, PixelFormat.Format32bppArgb);
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, region.Width, region.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            byte[] dataBuffer = new byte[region.Width * 4];
            for (int i = 0; i < region.Height; i++)
            {
                Marshal.Copy(r.DataPointer, dataBuffer, 0, region.Width * 4);
                Marshal.Copy(dataBuffer, 0, data.Scan0, region.Width * 4);

                r.DataPointer += r.Pitch;
                data.Scan0 += region.Width * 4;
            }

            bmp.UnlockBits(data);
            target.UnlockRectangle();

            target.Dispose();

            return bmp;
        }
    }
}
